/*
 * @FilePath: \Src\BSP\src\drv_key.c
 * @Description:
 *
 * Copyright (c) 2025 by ${w}, All Rights Reserved.
 */

#include "main.h"

/* 可注册的按键数量 */
#define MAX_BUTTON 1

/* 时间参数 */
#define DEBOUNCE_TICKS 2         // 消抖周期
#define DOUBLE_INTERVAL_TICKS 20 // 双击间隔周期
#define LONG_PRESS_TICKS 100     // 长按周期
#define VLONG_PRESS_TICKS 300    // 超长按按周期
#define CONTINUOS_PRESS_TICKS 25 // 连按触发时间间隔

/* 按键状态 */
typedef enum
{
    /* 空闲 */
    BUTTON_IDLE,
    /* 消抖 */
    BUTTON_DEBONUCE,
    /* 确认按下计时 */
    BUTTON_PRESSED,
    /* 等待第二次点击 */
    BUTTON_WAIT_SECOND_CLICK,
    /* 长按计时 */
    BUTTON_LONG_PRESS,
    /* 超长按计时 */
    BUTTON_VLONG_PRESS
} ButtonState;

/* 按键控制结构体 */
typedef struct
{
    /* 用户配置 */
    ButtonConfig config;
    /* 按键状态 */
    ButtonState state;
    /* 按键按下计时 */
    unsigned short tick_cnt;
    /* 消抖计时 */
    unsigned short debounce_cnt;
    /* 上次电平 */
    unsigned char last_level;
    /* 案件按下次数 */
    unsigned char click_cnt;
} Button;

/* 按键数组 */
static Button buttons[MAX_BUTTON];
/* 记录当前已注册的 */
static unsigned char button_count = 0;

/**
 * @Author: YuluoY
 * @Date: 2025-06-15
 * @LastEditors: yuluoY
 * @LastEditTime: Do not edit
 * @Description:
 * @return {}
 */
void Button_Register(ButtonConfig *config)
{
    /* 按键数量大于最大值 */
    if (button_count > MAX_BUTTON)
    {
        PRINT_ERR("The registration failed if the number of keys exceeded the limit");
        return;
    }
    /* 传入指针为空 */
    if (config == key_ptr || config->read_keyValue == key_ptr)
    {
        PRINT_ERR("The registration failed if The key-value reading function is not implemented");
        return;
    }

    /* 用户按键配置 */
    buttons[button_count].config = *config;
    /* 默认空闲 */
    buttons[button_count].state = BUTTON_IDLE;
    /* 计数器清零 */
    buttons[button_count].tick_cnt = 0;
    /* 双击间隔计数器清零 */
    buttons[button_count].debounce_cnt = 0;
    /* 上次电平状态置为未触发 */
    buttons[button_count].last_level = !config->trigger_level;
    /* 点击次数清零 */
    buttons[button_count].click_cnt = 0;
    /* 按钮数量累加 */
    button_count++;
}

/**
 * @Author: YuluoY
 * @Date: 2025-06-15
 * @LastEditors: yuluoY
 * @LastEditTime: Do not edit
 * @Description: 按钮扫描
 * 注意此函数写法每次按下松开，按下和释放的回调是必然触发的
 * 注意连按事件仅触发在长按事件的基础上，所以注册了连按后，超长按是不生效的
 * @return {}
 */
void Button_Scan(void)
{
    unsigned char i = 0;
    unsigned char level;
    Button *btn = key_ptr;

    for (i = 0; i < MAX_BUTTON; i++)
    {
        /* 获取按钮的操作指针 */
        btn = &buttons[i];
        /* 读取当前按钮的电平状态 */
        level = btn->config.read_keyValue();

        switch (btn->state)
        {
        case BUTTON_IDLE:
            /* 确认按钮按下 进入消抖 */
            if (level == btn->config.trigger_level)
            {
                btn->state = BUTTON_DEBONUCE;
                /* 清除双击间隔 */
                btn->debounce_cnt = 0;
                /* 清除点击次数 */
                btn->click_cnt = 0;
            }
            break;

        case BUTTON_DEBONUCE:
            /* 消抖状态按钮任然按下 */
            if (level == btn->config.trigger_level)
            {
                /* 消抖时间累加 */
                if (btn->debounce_cnt < 0xFFFE)
                {
                    btn->debounce_cnt++;
                }
                /* 大于设定的消抖时间 进入按钮按下确认状态 */
                if (btn->debounce_cnt >= DEBOUNCE_TICKS)
                {
                    btn->state = BUTTON_PRESSED;
                    /* 按下时间清零 */
                    btn->tick_cnt = 0;
                    /* 触发按钮按下回调 */
                    btn->config.button_cb(btn->config.id, BUTTON_EVENT_PRESS_DOWN);
                }
            }
            else
            {
                /* 未完成消抖 回到空闲 */
                btn->state = BUTTON_IDLE;
            }
            break;

        case BUTTON_PRESSED:
            /* 按钮松开了 */
            if (level != btn->config.trigger_level)
            {
                /* 进入等待第二次按下状态 为判定双击做准备 */
                btn->state = BUTTON_WAIT_SECOND_CLICK;
                /* 按下时间清零 */
                btn->tick_cnt = 0;
                /* 触发松开回调 */
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_RELEASE);

                /* 注意此处 点击事件和点击事件不能同时触发 */
                /* 如果注册了双击事件 那么点击次数累加 */
                if (btn->config.event_mask & BUTTON_EVT_DOUBLE_CLICK)
                {
                    if (btn->click_cnt < 0xFE)
                    {
                        btn->click_cnt++;
                    }
                }
                /* 如果注册的是单击事件 那么按下松开为一次点击 触发点击回调 */
                else if (btn->config.event_mask & BUTTON_EVT_CLICK)
                {
                    btn->config.button_cb(btn->config.id, BUTTON_EVENT_CLICK);
                }
            }
            else
            {
                /* 按钮仍然按下 按下时间累加 */
                if (btn->tick_cnt < 0xFFFE)
                {
                    btn->tick_cnt++;
                }

                /* 注册了长按事件 按下时间大于设定时间 */
                if ((btn->config.event_mask & BUTTON_EVT_LONG_PRESS) && btn->tick_cnt >= LONG_PRESS_TICKS)
                {
                    /* 进入长按事件 触发长按回调 */
                    btn->state = BUTTON_LONG_PRESS;
                    btn->config.button_cb(btn->config.id, BUTTON_EVENT_LONG_PRESS);
                }
            }
            break;
        case BUTTON_LONG_PRESS:
            /* 在按钮未松开时时间累加 */
            if (btn->tick_cnt < 0xFFFE)
            {
                btn->tick_cnt++;
            }

            /* 如果注册了连按事件 */
            if ((btn->config.event_mask & BUTTON_EVT_CONTINUOS_PRESS) && btn->tick_cnt >= CONTINUOS_PRESS_TICKS)
            {
                btn->tick_cnt = btn->tick_cnt - CONTINUOS_PRESS_TICKS;
                /* 触发连按回调 */
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_CONTINUOS_PRESS);
            }

            /* 如果注册了超长按并且时间大于设定时间 */
            if ((btn->config.event_mask & BUTTON_EVT_VLONG_PRESS) && btn->tick_cnt >= VLONG_PRESS_TICKS)
            {
                /* 进入超长按 */
                btn->state = BUTTON_VLONG_PRESS;
                /* 触发超长按回调 */
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_VLONG_PRESS);
            }
            /* 按钮释放了 回到空闲并且触发释放回调 */
            if (level != btn->config.trigger_level)
            {
                btn->state = BUTTON_IDLE;
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_RELEASE);
            }
            break;

        case BUTTON_VLONG_PRESS:
            /* 超长按等待按键释放 */
            if (level != btn->config.trigger_level)
            {
                btn->state = BUTTON_IDLE;
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_RELEASE);
            }
            break;

        case BUTTON_WAIT_SECOND_CLICK:
            /* 等待双击的第二次按下 时间累加 */
            if (btn->tick_cnt < 0xFFFE)
            {
                btn->tick_cnt++;
            }
            /* 第二次按下了并且时间小于双击间隔 回到按下确认状态 */
            if (level == btn->config.trigger_level)
            {
                btn->state = BUTTON_PRESSED;
                btn->tick_cnt = 0;
                btn->config.button_cb(btn->config.id, BUTTON_EVENT_PRESS_DOWN);
            }
            /* 如果时间大于双击间隔了 */
            else if (btn->tick_cnt >= DOUBLE_INTERVAL_TICKS)
            {
                /* 判断按钮按下的次数 如果注册有双击事件 按下次数大于1次 */
                if (btn->click_cnt > 1 && (btn->config.event_mask & BUTTON_EVT_DOUBLE_CLICK))
                {
                    /* 触发双击回调 */
                    btn->config.button_cb(btn->config.id, BUTTON_EVENT_DOUBLE_CLICK);
                    btn->click_cnt = 0;
                }
                /* 清除时间 */
                btn->tick_cnt = 0;
                btn->state = BUTTON_IDLE;
            }
            break;

        default:
            break;
        }
    }
}
